home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / a86masm.arc / A86-MASM
Text File  |  1987-05-16  |  33KB  |  696 lines

  1. A DISCUSSION OF A86'S ADVANTAGES OVER MICROSOFT'S MASM ASSEMBLER
  2. by Eric Isaacson
  3.  
  4. In this paper, I'll describe in detail the superiority of my A86 
  5. assembler over the largest-selling assembler for the IBM-PC, the 
  6. MASM assembler, V4.00, marketed by both IBM and Microsoft.  I'll 
  7. cover these topics: 
  8.  
  9. 1. Speed of assembly.
  10.  
  11. 2. Code generation (yes, it's possible for an assembler to 
  12.    generate better code!)
  13.  
  14. 3. Quality of error messages.
  15.  
  16. 4. Library facilities.
  17.  
  18. 5. Extra language features.
  19.  
  20.  
  21. Speed of Assembly
  22.  
  23. Until some months after A86 was introduced, Microsoft advertised 
  24. MASM V4.00 as "the fastest MS-DOS macro assembler, bar none."  
  25. A86 completely shatters this claim, as the following data show.
  26. To provide a good profile of execution speed, I assembled four
  27. programs, each on four different computers.  On each computer I 
  28. assembled the programs twice; once in which the assembler and the 
  29. programs are all on a RAM disk, and once in which the assembler 
  30. and the programs are on the non-RAM storage medium for the 
  31. computer-- a hard disk for two of the computers, a floppy disk 
  32. for the other two.  No attempt was made to insure that files 
  33. appeared contiguously on the disks.
  34.  
  35. For each assembly I measured four times-- the A86 V3.02 execution 
  36. time, the MASM V4.00 execution time, the time it takes to copy 
  37. the source program to the NUL device, and the total execution 
  38. time for MASM, LINK, and EXE2BIN (necessary with MASM to produce 
  39. the COM file that A86 produces all by itself). 
  40.  
  41. I then used the times to produce four ratios for each program 
  42. run:
  43.  
  44. 1. The ratio of MASM's execution time to A86's execution time.
  45.  
  46. 2. The same ratio, with the copy-source times subtracted from 
  47.    each assembler's time.  Subtracting the copy-source time 
  48.    provides a more accurate measure of actual assembly time, 
  49.    apart from the minimum time the assembler would have to wait 
  50.    for MSDOS to read the source program. 
  51.  
  52. 3. The ratio of MASM+LINK+EXE2BIN's execution time to A86's 
  53.    execution time. 
  54.  
  55. 4. The same ratio, with the copy-source times subtracted.
  56.  
  57. The four programs that I used are as follows:
  58.  
  59. HUGE is a program that consists of a few memory variable 
  60.    definitions, and many copies of the entire 286 instruction 
  61.    set.  The hugeness is achieved by 20 repetitions of the same 
  62.    instruction-set file, given as INCLUDEs to MASM, and as 
  63.    invocation-file names to A86.  Both MASM and A86 blissfully 
  64.    fail to notice that they are assembling the same file 
  65.    repeatedly, so that it is as if 20 different files are being 
  66.    assembled.  The main file is 51 lines, 527 bytes, and the 
  67.    include file is 500 lines, 40000 bytes.  So the total assembly 
  68.    is 10051 lines, 800527 bytes. 
  69.  
  70. COMM is the same program as HUGE, except that the first character 
  71.    of every line of the INCLUDE-file is replaced with a semi-
  72.    colon.  Comparing the times of HUGE and COMM give an 
  73.    indication of how much longer it takes the assemblers to 
  74.    process real instructions than it does to chew through 
  75.    comments.
  76.  
  77. NORM is a real-life program, WS-ASCII by Michael Hoyt, which was 
  78.    written for MASM but which A86 assembles without modification.  
  79.    The program has 434 lines, 17272 bytes.
  80.  
  81. TINY is a program consisting of a single NOP instruction, 
  82.    together with the minimum amount of MASM red-tape directives 
  83.    to produce a COM file.  The program has 7 lines, 90 bytes.
  84.  
  85. The four computers I used are as follows:
  86.  
  87. AT is a 9MHz IBM PC-AT with 512K of RAM and a PRIAM hard disk.
  88.  
  89. LE is a 4.77MHz Leading Edge Model "D" with 640K of RAM and a
  90.     30MHz Hard Disk.
  91.  
  92. PC is a 4.77MHz IBM PC with 512K of RAM and a floppy drive.
  93.  
  94. ZEN is an 8MHz Zenith 159 PC with 512K of RAM and a floppy drive.
  95.  
  96.  
  97. Table 1 shows the execution times (in seconds) gathered, and 
  98. Table 2 shows the resulting ratios.   The subjective impression 
  99. is that A86 execution speed is limited only by the speed of the 
  100. file input/output (in fact, one user reports that A86 assembles 
  101. his source files faster than his editor saves them).  The 
  102. impression holds true in the case of the floppy-based Zenith 
  103. computer-- A86 actually assembled the HUGE and COMM programs 
  104. faster than COPY concatenated the source files!  For all the 
  105. other cases, however, the tables reveal a distinct measurable 
  106. difference between the time it takes to assemble files and the 
  107. time it takes to read the files with the COPY program. 
  108.  
  109. ------------------------------------------------------------------
  110. TABLE 1.  Execution Times for MASM vs. A86 for Four Programs
  111.  
  112.               Programs:   HUGE     COMM     NORM     TINY
  113. Computers:
  114.  
  115.     Hard AT  MASM        86.33    30.67     3.51     1.48
  116.     Hard AT  A86         14.94     9.66     0.99     0.88
  117.     Hard AT  COPY        10.33     9.50     0.27     0.11
  118.     Hard AT  MASM->COM  100.24    33.06     5.43     2.13
  119.  
  120.     RAM AT   MASM        55.62    13.14     1.98     0.44
  121.     RAM AT   A86          6.23     2.30     0.44     0.27
  122.     RAM AT   COPY         2.03     2.03     0.11     0.11
  123.     RAM AT   MASM->COM   62.12    13.64     2.67     0.94
  124.  
  125.     HARD LE  MASM       314.18    77.46    11.29     2.68
  126.     HARD LE  A86         31.16    12.56     2.50     1.43
  127.     HARD LE  COPY        11.47    10.98     0.60     0.50
  128.     HARD LE  MASM->COM  355.27    81.00    16.16     6.18
  129.  
  130.     RAM LE   MASM       249.14    58.99     8.46     1.59
  131.     RAM LE   A86         24.88     9.17     1.53     0.88
  132.     RAM LE   COPY         8.02     8.02     0.38     0.33
  133.     RAM LE   MASM->COM  261.79    61.14    11.26     3.73
  134.  
  135.     FLOP PC  MASM       417.71   232.11    25.21    15.54
  136.     FLOP PC  A86        104.14    87.66    11.54     7.25
  137.     FLOP PC  COPY        78.05    79.26     3.51     1.38
  138.     FLOP PC  MASM->COM  487.85   256.72    52.95    39.71
  139.  
  140.     RAM PC   MASM       249.58    59.32     8.90     2.03
  141.     RAM PC   A86         25.26     9.67     1.81     1.15
  142.     RAM PC   COPY         8.18     8.24     0.44     0.33
  143.     RAM PC   MASM->COM  279.73    61.63    11.81     4.28
  144.  
  145.     FLOP ZEN MASM       314.54   269.24    27.19    20.55
  146.     FLOP ZEN A86        118.58   114.74    13.73    10.16
  147.     FLOP ZEN COPY       122.71   122.98     4.62     2.53
  148.     FLOP ZEN MASM->COM  398.29   297.42    59.38    48.78
  149.  
  150.     RAM ZEN  MASM       140.88    35.65     5.05     0.88
  151.     RAM ZEN  A86         14.83     5.33     0.88     0.44
  152.     RAM ZEN  COPY         4.78     4.78     0.22     0.17
  153.     RAM ZEN  MASM->COM  169.45    36.86     6.65     2.14
  154.  
  155. ------------------------------------------------------------------
  156.    
  157. As you might expect, the most consistent results are obtained 
  158. when a RAM disk is used.  The ratios don't differ very much from 
  159. computer to computer.  They reveal A86 to be an order of 
  160. magnitude (ten times) faster than MASM at the simple assembly of 
  161. large programs, about five times faster for the normal-sized 
  162. program.  In no case does A86 perform an anything less than half-
  163. again the speed of MASM.  I have been claiming that A86 is five 
  164. times as fast as MASM overall; and these results bear me out.
  165.  
  166. ------------------------------------------------------------------
  167.  
  168.     TABLE 2.  Ratios of MASM Times to A86 Times
  169.  
  170.               Programs:   HUGE     COMM     NORM     TINY
  171. Computers:
  172.  
  173.     Hard AT  ASM           5.8      3.2      3.5      1.7
  174.     Hard AT  ASM-COPY     16.5    132.3      4.5      1.8
  175.     Hard AT  COM           6.7      3.4      5.5      2.4
  176.     Hard AT  COM-COPY     19.5    147.2      7.2      2.6
  177.  
  178.     RAM AT   ASM           8.9      5.7      4.5      1.6
  179.     RAM AT   ASM-COPY     12.8     41.1      5.7      2.1
  180.     RAM AT   COM          10.0      5.9      6.1      3.5
  181.     RAM AT   COM-COPY     14.3     43.0      7.8      5.2
  182.  
  183.     HARD LE  ASM          10.1      6.2      4.5      1.9
  184.     HARD LE  ASM-COPY     15.4     42.1      5.6      2.3
  185.     HARD LE  COM          11.4      6.4      6.5      4.3
  186.     HARD LE  COM-COPY     17.5     44.3      8.2      6.1
  187.  
  188.     RAM LE   ASM          10.0      6.4      5.5      1.8
  189.     RAM LE   ASM-COPY     14.3     44.3      7.0      2.3
  190.     RAM LE   COM          10.5      6.7      7.4      4.2
  191.     RAM LE   COM-COPY     15.1     46.2      9.5      6.2
  192.  
  193.     FLOP PC  ASM           4.0      2.6      2.2      2.1
  194.     FLOP PC  ASM-COPY     13.0     18.2      2.7      2.4
  195.     FLOP PC  COM           4.7      2.9      4.6      5.5
  196.     FLOP PC  COM-COPY     15.7     21.1      6.2      6.5
  197.  
  198.     RAM PC   ASM           9.9      6.1      4.9      1.8
  199.     RAM PC   ASM-COPY     14.1     35.7      6.2      2.1
  200.     RAM PC   COM          11.1      6.4      6.5      3.7
  201.     RAM PC   COM-COPY     15.9     37.3      8.3      4.8
  202.  
  203.     FLOP ZEN ASM           2.7      2.3      2.0      2.0
  204.     FLOP ZEN ASM-COPY  infinity infinity     2.5      2.4
  205.     FLOP ZEN COM           3.4      2.6      4.3      4.8
  206.     FLOP ZEN COM-COPY  infinity infinity     6.0      6.1
  207.  
  208.     RAM ZEN  ASM           9.5      6.7      5.7      2.0
  209.     RAM ZEN  ASM-COPY     13.5     56.1      7.3      2.6
  210.     RAM ZEN  COM          11.4      6.9      7.6      4.9
  211.     RAM ZEN  COM-COPY     16.4     58.3      9.7      7.3
  212.  
  213. ------------------------------------------------------------------
  214.  
  215. Another claim I have made is that A86 assembles 1000 lines per 
  216. second under the best conditions (8MHz AT with a RAM disk or 
  217. contiguous files on a fast hard disk).  This claim was based on 
  218. observations of A86 assembling itself.  I put a line-counter into 
  219. A86, and used it to count the source lines.  The counter treated 
  220. macro-expansion lines as separate lines to be counted (which 
  221. seems fair to me).  Since the original measurement was made, 
  222. A86's performance assembling itself has eroded, and my claim as 
  223. appropriately restricted (to contiguous files on a fast hard 
  224. disk).
  225.  
  226. This more extensive and organized study illuminates my claim in 
  227. several ways.  There was more of a difference between a 
  228. hard disk and a RAM disk than I realized.  With a RAM disk, A86 
  229. assembles 1434 instruction lines a second; and over 4000 comment 
  230. lines a second.  A large, heavily-commented program should 
  231. assemble at around 2000 lines per second.  With a hard disk, the 
  232. time for assembly of instructions slows to around 600 lines per 
  233. second.  By subtracting the time for execution of a COPY of the 
  234. source files, we obtain a closer estimate of the time A86 spends 
  235. assembling, rather than waiting for the input.  Under this 
  236. measure, A86 assembles instructions at 2127 lines per second; 
  237. comments at well over 10000 lines per second (the time for 
  238. assembling comments is so close to the time for copying comments 
  239. that the measure yields wildly-differing, near-infinite rates of 
  240. assembly).
  241.  
  242. To summarize: A86 is outrageously fast, and MASM isn't.
  243.  
  244.  
  245.  
  246. Ease of Use
  247.  
  248. Assembly language is routinely condemned by computer literature.  
  249. The primary thrust of most criticism is that programs are more 
  250. difficult to write in assembly language than they are in high-
  251. level language.  Intel aggravated the problem when it designed 
  252. the 8086 assembly language, by forcing users to provide numerous 
  253. directives in every program to describe the segmentation model 
  254. being used, even when the program does not concern itself with 
  255. segmentation.  I call these directives "red-tape directives".  
  256. MASM followed Intel's lead in requiring them; as a result, many 
  257. programmers have been deterred from using (or even learning!) 
  258. assembly language because of the intimidating nature of the red-
  259. tape directives. 
  260.  
  261. For compatibility, A86 recognizes the red-tape directives 
  262. required by MASM.  But A86 also has a set of defaults that make 
  263. the red-tape directives unnecessary.  If you wish to code a 
  264. program consisting of 10 lines, your source file can consist of 
  265. the 10 lines and nothing else.  A86 will assemble the 10-line 
  266. file directly to a COM file, ready to be executed immediately.  
  267. With MASM, you must discern and code the extra red-tape 
  268. directives.  After assembling the file, you must feed the 
  269. resulting OBJ file to LINK to obtain an executable EXE file.  If 
  270. you want the simpler, more compact COM format, you must feed the 
  271. EXE file to a program called EXE2BIN. 
  272.  
  273. A particularly annoying feature of the process just described is 
  274. a pair of conflicting requirements: to LINK with no errors, you 
  275. must declare a STACK segment, but to get EXE2BIN to give you a 
  276. COM file, there must be no STACK segment.  You must resolve this 
  277. conflict in favor of EXE2BIN by omitting the STACK segment, and 
  278. have LINK always tell you that you had 1 error. 
  279.  
  280. A86 also has a good set of default settings for writing 
  281. subroutines to be called by high-level language programs.
  282. For example, if your C program calls a function MUL10, that 
  283. multiplies its single operand by 10, you can code MUL10 with
  284. A86 as follows:
  285.  
  286. _MUL10:             ; leading underscore required by compiler
  287.   PUSH BP           ; "C" expects BP to be preserved
  288.   MOV BP,SP         ; we use BP to address the stack
  289.   MOV AX,[BP+4]     ; fetch the number N, beyond BP and the return address
  290.   ADD AX,AX         ; 2N
  291.   MOV BX,AX         ; 2N is saved in BX
  292.   ADD AX,AX         ; 4N
  293.   ADD AX,AX         ; 8N
  294.   ADD AX,BX         ; 8N + 2N = 10N
  295.   POP BP            ; BP is restored
  296.   RET               ; go back to caller
  297.  
  298. The above 11 lines can be the entire source file!  If the file is 
  299. named MUL10.8, then the command A86 MUL10.8 MUL10.OBJ will 
  300. produce an OBJ file compatible with the standard SMALL model of 
  301. computation (substitute RETF for RET in the file and you'll get 
  302. the LARGE model).  The OBJ file contains a PUBLIC symbol record 
  303. for _MUL10; the code will be placed into a segment named _TEXT, 
  304. with the appropriate combination-types.  If there had been any 
  305. references to undefined symbols in the file, those symbols would 
  306. have automatically been declared external in the OBJ file.
  307.  
  308. MASM places a barrier of confusing directives between the user 
  309. and the program.  A86 lets the user concentrate on the program, 
  310. and provide the directives only when they are needed to do 
  311. something unusual.
  312.  
  313.  
  314. Code Generation
  315.  
  316. In an effort to make A86 as compatible as possible with MASM, I 
  317. have assembled dozens of publicly-available source files.  While 
  318. doing this, I made a surprising discovery: A86 generates better 
  319. code than MASM does!  Many programs wind up a few bytes smaller 
  320. under A86 than they do under MASM.  Here's why:
  321.  
  322. 1. I've noticed that the LEA (Load Effective Address) instruction 
  323.    is misused by many programmers.  LEA is essentially a register 
  324.    arithmetic instruction; for example, LEA AX,[BX+SI+200] adds 
  325.    200 into the contents of the BX and SI registers, and stores 
  326.    the 3-item sum in the AX register.  No memory reference is 
  327.    made.  Many programmers use LEA to load a simple offset into a 
  328.    register: they code LEA SI,BVAR instead of the more verbose 
  329.    MOV SI,OFFSET BVAR.  However, the LEA instruction consumes one 
  330.    more byte of object code than the equivalent MOV instruction. 
  331.    When I saw this, I decided to make A86 generate the shorter 
  332.    MOV instruction when it sees an LEA of a simple memory 
  333.    variable, or of a single-register index with no displacement. 
  334.  
  335. 2. I already mentioned that LEA does not reference memory-- the 
  336.    memory address, not the memory contents, is loaded into the 
  337.    destination register.  Thus, if there is a segment-override 
  338.    associated with the memory address, there is no point in 
  339.    providing the override opcode byte.  MASM, however, will 
  340.    generate that opcode byte if the memory operand is not ASSUMEd 
  341.    to be in the default segment register for the operand.  This 
  342.    override opcode is ignored by the processor when the program 
  343.    executes.  A86 does not generate this wasted override. 
  344.  
  345. 3. If you code a MOV or arithmetic instruction of an immediate 
  346.    value into a forward-referenced memory variable, A86 forces 
  347.    you to specify the size of the variable by appending a B or W 
  348.    to the first reference.  If the variable is byte-sized, you 
  349.    are rewarded for your extra effort: A86 will save a byte of 
  350.    code over MASM, which allocates enough space for a word in 
  351.    pass 1, then generates a wasted NOP instruction or a less-
  352.    efficient opcode form in pass 2 when it sees that only a byte 
  353.    is needed. 
  354.  
  355. 4. If you code a JMP to a forward-referenced label, there is no 
  356.    good way for MASM to tell if a short (within 128 bytes) JMP 
  357.    will suffice, without your explicitly forcing it with the 
  358.    SHORT operator.  A86 assumes that a JMP to a forward-
  359.    referenced local label is short.  Thus, if you don't pay close 
  360.    attention to this sort of thing, your program will be shorter 
  361.    with A86.  (If it is a long jump, you can override with the 
  362.    LONG operator; or you can disable this feature entirely with 
  363.    the L switch.) 
  364.  
  365. 5. There is an obscure code optimization that can be performed in 
  366.    the following case: suppose you have a procedure that is to be 
  367.    called both from within and without its code segment.  The 
  368.    procedure must return via RETF to handle far calls 
  369.    successfully.  This means that the CS register must be pushed 
  370.    onto the stack even when the procedure is called from within 
  371.    its own segment.  The straightforward way of doing this is via 
  372.    a FAR call, with the operand containing the same segment-
  373.    register value as the caller.  An optimization that saves both 
  374.    program space and execution time is to do a PUSH CS followed 
  375.    by a near CALL to the procedure.  A86 performs this 
  376.    optimization when it sees the chance; MASM doesn't. 
  377.  
  378. 6. Finally, I can't resist mentioning that A86 produces much more 
  379.    efficient .OBJ files than MASM does.  The efficiencies I refer 
  380.    to here won't necessarily show up in the final program; but 
  381.    they make .OBJ files smaller (saving disk space if you have 
  382.    libraries) and they will make linking and loading faster.  
  383.    Some examples: 
  384.  
  385.    a. If your source file has interspersed fragments of different 
  386.       segments (e.g. code and data segments), A86 will link 
  387.       together the fragments of each segment before outputting 
  388.       their contents to the OBJ file.  MASM will keep the output 
  389.       fragmented into separate object-contents records. 
  390.  
  391.    b. If you have a sequence of PUBLIC symbols all from the same 
  392.       segment, A86 will output them all in one record.  MASM 
  393.       always outputs a different record for each public symbol.
  394.       Each wasted record increases the OBJ file size by 6 bytes.
  395.  
  396.    c. MASM always produces inefficient records for DUP 
  397.       constructs.  The innermost part of any nested DUP, 
  398.       containing the actual data to be duplicated, will always be 
  399.       given by MASM as a nested DUP with a count of 1.  For 
  400.       example, 4 DUP (5) is encoded by MASM as if it were
  401.       4 DUP (1 DUP (5)).  A86 avoids such inefficiency.
  402.  
  403.    d. If you CALL a procedure within the same segment as the CALL
  404.       instruction, the assembler should generate a relative count 
  405.       of the distance from the end of the CALL to the beginning 
  406.       of the procedure.  This count can be determined at assembly 
  407.       time, even if the segment is relocated.  But MASM doesn't 
  408.       bother; it generates a fix-up record in the OBJ file and 
  409.       lets the linker perform the subtraction.  This wastes 11 
  410.       bytes for the first CALL, and 7 bytes for each subsequent 
  411.       CALL within an object-contents record. 
  412.  
  413.  
  414.  
  415. Quality of Error Messages
  416.  
  417. A86 makes error-correcting much easier by inserting messages 
  418. directly into the source file, at the point where they occurred.  
  419. There is also a less immediately obvious improvement in error 
  420. reporting: the quality of the messages themselves.
  421.  
  422. The content of error messages isn't too important for expert 
  423. assembly-language programmers -- a general hint as to the nature 
  424. of the problem is enough for the expert to solve it.  But for 
  425. novice programmers, good error messages can save hours of 
  426. frustration.  I've given a lot of thought to my error messages.  
  427. In some cases, I've actually added code to A86 to diagnose errors 
  428. after they have been detected, to provide a more descriptive 
  429. message.  As a result, A86 provides error-reporting superior to 
  430. MASM's reporting. 
  431.  
  432. Some A86 error messages are spectacularly more descriptive than 
  433. MASM's messages, because A86 has a much better idea of what went 
  434. wrong than MASM does.  Some examples: 
  435.  
  436.     ROR AL 
  437.           MASM: Syntax error 
  438.           A86:  More Operands Required
  439.  
  440.     MOV AX,(5*(17+56/(32+4)) 
  441.           MASM: Syntax error 
  442.           A86:  Parenthesis/Bracket Mismatch
  443.  
  444.     MOV AL,FOO 
  445.     ......
  446.     FOO DW ? 
  447.           MASM, first line:  Operand types must match 
  448.           MASM, second line: Phase error between passes 
  449.           A86, second line:  Definition Conflicts With Forward
  450.                                  Reference
  451.  
  452. In other cases, it appears that MASM has just as good an idea of 
  453. the problem; but A86's phrasing of the error message is clearer 
  454. for novice programmers.  Examples:
  455.                                  
  456.     MOV ES,0 
  457.           MASM: No immediate mode 
  458.           A86:  MOV Segment Register,Immediate Not Allowed
  459.  
  460.     INC DS:[BX] 
  461.           MASM: Operand must have size 
  462.           A86:  Is It Byte Or Word?
  463.  
  464.     STC 17 
  465.           MASM: Extra characters on line 
  466.           A86:  Operands Not Allowed
  467.  
  468.     MOV AX,[BX+BP] 
  469.           MASM: Already have base register 
  470.           A86:  [BX+BP] And [SI+DI] Not Allowed
  471.     
  472.  
  473. Library Facilities
  474.  
  475. A common complaint against assembly language is its lack of 
  476. built-in power.  Most high-level languages have features for 
  477. formatting, input/output, and/or numerical computation, that can 
  478. be accessed with relative ease.  To overcome this limitation you 
  479. can build up a library of routines that perform these functions, 
  480. and call procedures from the library.
  481.  
  482. Both MASM and A86 allow you to build libraries of object files.  
  483. In order to call a library subroutine using MASM, you must 
  484. declare the subroutine at the top of every module that uses it, 
  485. using the EXTRN directive.  Then you must tell LINK where to find 
  486. the library that contains your subroutine.  A86 allows you to 
  487. improve upon this scenario slightly, by not requiring the EXTRN 
  488. directive in the calling module (or, for that matter, the PUBLIC 
  489. directive in the library module).
  490.  
  491. For programs written entirely in assembly language, a much more 
  492. significant improvement is offered by A86's source library 
  493. facility.  You feed the library files to the A86LIB tool, and put 
  494. a SET A86LIB to the drive and/or directory into your AUTOEXEC.BAT 
  495. file.  Once you've done that, the library is set up, and calling 
  496. it is totally effortless and automatic.  Whenever A86 sees any 
  497. undefined symbols, it looks for them in the libraries in the 
  498. current directory and in the A86LIB-environment directories.  If 
  499. you don't use the library. no time is wasted unless you 
  500. mistakenly leave a symbol undefined.  Also, since A86 assembles 
  501. source files faster than LINK links object files, the whole 
  502. process occurs much more quickly than if LINK is used.
  503.  
  504. There is another advantage to source file libraries over object 
  505. libraries-- a dimension of flexibility for symbols defined by the 
  506. main program and used by the library.  There are several 
  507. manifestations of this:
  508.  
  509. 1. A quantity such as an array limit could be an assembly-time 
  510.    constant in some programs, and a run-time variable in others.  
  511.    Since the 86 language defines the same syntax for immediate-
  512.    operand instructions as for variable-operand instructions, the 
  513.    library can access the array limit without knowing whether it 
  514.    is constant or variable.  Then the calling program can define 
  515.    the limit using EQU or DW as necessary.  Since the immediate-
  516.    versus-variable ambiguity exists at the source level and not 
  517.    the object-code level, an OBJ library must commit itself to 
  518.    the limit's type. 
  519.  
  520. 2. Similarly, a subroutine call might be direct in some programs 
  521.    and indirect in others.  An example of this is the LINES 
  522.    library module given as the sample in the A86 package.  The 
  523.    module gathers in standard input, and calls the routine 
  524.    PROCESS_LINE provided by the main program.  For simple filter 
  525.    programs, PROCESS_LINE will be a subroutine directly called by 
  526.    the library. More complicated programs might perform different 
  527.    actions on a line, depending on the line's context within the 
  528.    input stream.  For such programs, PROCESS_LINE can be a word-
  529.    variable pointing to the routine wanted, and the call to 
  530.    PROCESS_LINE will be indirect.  Again, an object-file library 
  531.    must commit to direct-versus-indirect. 
  532.  
  533. 3. The calling program could provide the definition for a macro 
  534.    used by the library routine, or the defintion of switches to 
  535.    control conditional assembly within the library.  This adds an 
  536.    arbitrary degree of specialization to the library routine, not 
  537.    possible with object libraries.  
  538.  
  539.  
  540.  
  541. Extra Language Features
  542.  
  543. A86's language extension features make A86 programs better and 
  544. easier to code than MASM programs.  The idea behind most of the 
  545. features is to make the typical program either shorter or less 
  546. cluttered.  Let's consider each feature in turn:
  547.  
  548. 1. LOCAL SYMBOLS. A86 allows symbols consisting of a single letter 
  549.    followed by one or more decimal digits (L3, X123, Y37, etc.) 
  550.    to be redefined within your program.  This allows such symbols 
  551.    to have local scope.  
  552.  
  553.    If you examine most assembler program symbol tables, you will 
  554.    find that the symbols can be partitioned into two levels of 
  555.    significance.   About half the symbols are the names of 
  556.    procedures and variables having global significance.  If the 
  557.    names of these symbols are chosen intelligently and carefully, 
  558.    the program's readability improves drastically. (They usually 
  559.    aren't chosen well, most often because the assembler restricts 
  560.    symbols to 6 letters, or because the programmer's habits are 
  561.    influenced by such assemblers.) 
  562.  
  563.    The other half of the symbols in a program have a much lower, 
  564.    local significance.  They are only place-markers used to 
  565.    implement small loops and local branching (e.g., "skip the 
  566.    next 2 instructions if the Z-flag is set").  Assigning full-
  567.    blown names to these labels reduces the readability of your 
  568.    program in two ways:  First, it is harder to recognize local 
  569.    jumps for what they are-- they are usually the assembly-
  570.    language equivalent of high-level language constructs like IF 
  571.    statements and WHILE-loops.  
  572.  
  573.    Second, it is harder to follow the global, significant symbols 
  574.    because they are buried in a sea of the place-marker symbols 
  575.    in the symbol table.  
  576.  
  577.    By assigning extremely short local names (typically L0 through 
  578.    L9) to the place-markers in your program, you eliminate the 
  579.    clutter of symbols.  The are also other advantages to be 
  580.    reaped from this practice: 
  581.    
  582.    a. Since the complete place-marker symbol is only two 
  583.       characters long, you can indent your program code only two 
  584.       spaces, and still be able to quickly spot the destinations 
  585.       to short jumps.  This gives you more room for literate 
  586.       comments on the instruction lines, which in turn reduces 
  587.       the number of full-line comments needed.  The whole program 
  588.       becomes less cluttered and more readable.
  589.  
  590.    b. The only global labels within your program's body will be 
  591.       procedure names.  The XREF symbol-table program keys on 
  592.       this, by collecting the name of the last global symbol 
  593.       defined for each global symbol referenced.  Thus the XREF 
  594.       cross-reference is at the procedure level, making an A86 
  595.       XREF much more useful than other cross reference listings, 
  596.       which give either line numbers (too precise) or module 
  597.       names (not precise enough).
  598.  
  599.    c. Your re-use of a local symbol name causes A86's internal 
  600.       storage area for that name to be re-used as well.  This 
  601.       effectively doubles your symbol-table capacity.
  602.  
  603.  
  604. 2. DUPLICATE DEFINITIONS.  Not to be confused with local symbols, 
  605.    the duplicate definition feature allows you to redefine the 
  606.    same global symbol, as long as each succeeding definition has 
  607.    the same value as the first.  This has two uses: 
  608.  
  609.    First, it eases modular program development.  For example, if 
  610.    two independently-developed source files both use the symbol 
  611.    ESC to stand for the ASCII code for ESCAPE, they can both 
  612.    contain the declaration ESC EQU 01B, with no problems if they 
  613.    are combined into the same program.  
  614.  
  615.    The second use for this feature is assertion-checking.  Your 
  616.    deliberate redeclaration of a symbol name is an assertion that 
  617.    the value of the symbol has not changed; and you want the 
  618.    assembler to issue you an error message if it has changed.  
  619.    Example: suppose you have declared a table of options in your 
  620.    DATA segment; and you have another table of initial values for 
  621.    those options in your CODE segment.  If you come back months 
  622.    later and add an option to your tables, you want to be 
  623.    reminded to update both tables in the same way.  You should 
  624.    declare your tables as follows: 
  625.  
  626.    DATA SEGMENT
  627.      OPTIONS:
  628.        .
  629.        .
  630.      OPT_COUNT EQU $-OPTIONS    ; OPT_COUNT is the size of the table
  631.  
  632.    CODE SEGMENT
  633.      OPT_INITS:
  634.        .
  635.        .
  636.      OPT_COUNT EQU $-OPT_INITS  ; second OPT_COUNT had better be the same!
  637.  
  638.    Note that you can do assertion-checking in MASM, but that it 
  639.    requires extra language symbols, .ERRE and .ERRNZ, that you 
  640.    cannot possibly remember without looking in the manual.  Also, 
  641.    the above example is much more clean and unobtrusive in A86 
  642.    than it is in MASM. 
  643.  
  644. 3. CONDITIONAL RETURNS.  A86 allows the operand to a conditional 
  645.    jump instruction to be one of the three RET instructions RET, 
  646.    RETF, or IRET.  The assembler will find a nearby return-
  647.    instruction of the indicated flavor, and use that as the 
  648.    target for the conditional jump.  For example, JZ RET is the 
  649.    replacement for the 8080's RZ return-if-zero instruction.  
  650.    With MASM, you have to find the nearby instruction yourself, 
  651.    attach a label to it, and use that label.  Note that it does 
  652.    not suffice to attach a label to a single RET instruction and 
  653.    use that label throughout the program: the range of 
  654.    conditional jumps is only 128 bytes in either direction.  
  655.  
  656.    In addition to the obvious advantage in convenience, there is 
  657.    also an advantage in program readability.  If you want to make 
  658.    your programs both more readable and more modular, look for 
  659.    blocks of code containing several jumps to the same local-
  660.    label location.  If you find such a block, break it off into a 
  661.    separate procedure, ending at the local label being jumped to.  
  662.    The unconditional jumps to the local label become RET 
  663.    instructions; the conditional jumps become Jcond RET 
  664.    instructions. 
  665.  
  666. 4. OTHER SOURCE-SIMPLIFICATION FEATURES.  A86 has other code-
  667.    simplification features that make coding more convenient and 
  668.    programs more readable.  These are illustrated by the 
  669.    following A86 code fragments, alongside the longer equivalents 
  670.    that MASM forces on you:   
  671.  
  672.    A86 code                longer equivalent
  673.    --------                -----------------
  674.  
  675.    MOV AX,BX,VALUE         MOV BX,VALUE
  676.                            MOV AX,BX
  677.  
  678.    IF E MOV AL,BL          JNE BEYOND_MOVE
  679.                            MOV AL,BL
  680.                            BEYOND_MOVE:
  681.  
  682.    PUSH AX,BX,CX,DX        PUSH AX
  683.                            PUSH BX
  684.                            PUSH CX
  685.                            PUSH DX
  686.  
  687.    INC SI,2                INC SI
  688.                            INC SI
  689.  
  690.    TEST BX                 TEST BX,BX
  691.  
  692.    INC B[BX]               INC DS:BYTE PTR [BX]
  693.  
  694.    MOV FORWARD_VAR W,0     MOV WORD PTR FORWARD_VAR,0
  695.  
  696.